namespace Pinwheel.Kernel
{
    public delegate TaskCompletionSource<IMessage> MessageHandler(ref ServiceMessage message);
    
    public enum MessageHandlerType
    {
        Send,
        Receive
    }
    
    public abstract partial class ServiceBase : IComponentContainer, IMessageHandler
    {
        #region Events
        
        protected event MessageHandler OnSendHandler;
        protected event MessageHandler OnReceiveHandler;

        #endregion
        
        protected List<IComponent> ComponentSlots = new List<IComponent>();
        
        public void AddComponent<TComponent>(TComponent component) where TComponent : IComponent
        {
            ComponentSlots.Add(component);
            component.OnAttach(this);
        }
        
        public void RemoveComponent<TComponent>(TComponent component) where TComponent : IComponent
        {
            component.OnDetach(this);
            ComponentSlots.Remove(component);
        }
        
        public bool TryGetComponent<TComponent>(out TComponent component) where TComponent : IComponent
        {
            foreach (var slot in ComponentSlots)
            {
                if (slot is TComponent)
                {
                    component = (TComponent) slot;
                    return true;
                }
            }

            component = default;
            return false;
        }

        public void RegisterMessageHandler(MessageHandlerType type, MessageHandler handler)
        {
            switch (type)
            {
                case MessageHandlerType.Send:
                    OnSendHandler += handler;
                    break;
                case MessageHandlerType.Receive:
                    OnReceiveHandler += handler;
                    break;
            }
        }

        public void UnregisterMessageHandler(MessageHandlerType type, MessageHandler handler)
        {
            switch (type)
            {
                case MessageHandlerType.Send:
                    OnSendHandler -= handler;
                    break;
                case MessageHandlerType.Receive:
                    OnReceiveHandler -= handler;
                    break;
            }
        }

        public TaskCompletionSource<IMessage> InvokeMessageHandler(MessageHandlerType type, ref ServiceMessage message)
        {
            switch (type)
            {
                case MessageHandlerType.Send:
                    return OnSendHandler.Invoke(ref message);
                case MessageHandlerType.Receive:
                    return OnReceiveHandler.Invoke(ref message);
                default:
                    return null;
            }
        }
    }
}